/**
 * FTP客户端管理器
 * 支持断点续传和多并发传输
 */
const { Client } = require('basic-ftp');
const fs = require('fs');
const path = require('path');
const logger = require('./logger');
const config = require('./config');
const EventEmitter = require('events');

class FTPClient extends EventEmitter {
  constructor() {
    super();
    this.client = null;
    this.connected = false;
    this.currentDir = '/';
  }

  /**
   * 连接到FTP服务器
   */
  async connect(username, password) {
    try {
      this.client = new Client();
      this.client.ftp.verbose = false; // 关闭详细日志
      
      // 设置超时
      this.client.ftp.timeout = 30000; // 30秒超时

      const ftpConfig = config.getFtpConfig();
      logger.logFTP('尝试连接FTP服务器', { 
        host: ftpConfig.host, 
        port: ftpConfig.port,
        user: username 
      });

      await this.client.access({
        host: ftpConfig.host,
        port: ftpConfig.port,
        user: username,
        password: password,
        secure: false
      });

      this.connected = true;
      logger.logFTP('FTP连接成功', { user: username });
      this.emit('connected');
      
      return true;
    } catch (error) {
      const errorMsg = error.message || error.toString();
      logger.logFTP('FTP连接失败', { 
        user: username,
        error: errorMsg,
        code: error.code
      });
      this.connected = false;
      this.emit('connection-error', error);
      
      // 提供更友好的错误信息
      if (errorMsg.includes('ECONNREFUSED')) {
        throw new Error('FTP服务器连接被拒绝，请确保FTP服务已启动');
      } else if (errorMsg.includes('timeout')) {
        throw new Error('FTP连接超时，请检查网络连接');
      } else if (errorMsg.includes('530')) {
        throw new Error('FTP登录失败，用户名或密码错误');
      } else {
        throw new Error(`FTP连接失败: ${errorMsg}`);
      }
    }
  }

  /**
   * 断开连接
   */
  disconnect() {
    if (this.client) {
      this.client.close();
      this.client = null;
      this.connected = false;
      logger.logFTP('FTP连接已断开');
      this.emit('disconnected');
    }
  }

  /**
   * 列出目录内容
   */
  async list(dirPath = '.') {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      const list = await this.client.list(dirPath);
      return list.map(item => ({
        name: item.name,
        path: path.posix.join(dirPath === '.' ? this.currentDir : dirPath, item.name),
        isDirectory: item.type === 2,
        size: item.size,
        modified: item.modifiedAt
      }));
    } catch (error) {
      logger.logFTP('列出目录失败', { dirPath, error: error.message });
      throw error;
    }
  }

  /**
   * 切换目录
   */
  async cd(dirPath) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      await this.client.cd(dirPath);
      this.currentDir = await this.client.pwd();
      logger.logFTP('切换目录', { dirPath: this.currentDir });
      return this.currentDir;
    } catch (error) {
      logger.logFTP('切换目录失败', { dirPath, error: error.message });
      throw error;
    }
  }

  /**
   * 获取当前目录
   */
  async pwd() {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      this.currentDir = await this.client.pwd();
      return this.currentDir;
    } catch (error) {
      logger.logFTP('获取当前目录失败', { error: error.message });
      throw error;
    }
  }

  /**
   * 创建目录
   */
  async mkdir(dirPath) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      await this.client.send(`MKD ${dirPath}`);
      logger.logFTP('创建目录成功', { dirPath });
    } catch (error) {
      logger.logFTP('创建目录失败', { dirPath, error: error.message });
      throw error;
    }
  }

  /**
   * 删除文件
   */
  async deleteFile(filePath) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      await this.client.remove(filePath);
      logger.logFTP('删除文件成功', { filePath });
    } catch (error) {
      logger.logFTP('删除文件失败', { filePath, error: error.message });
      throw error;
    }
  }

  /**
   * 删除目录
   */
  async deleteDir(dirPath) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      await this.client.removeDir(dirPath);
      logger.logFTP('删除目录成功', { dirPath });
    } catch (error) {
      logger.logFTP('删除目录失败', { dirPath, error: error.message });
      throw error;
    }
  }

  /**
   * 上传文件（支持断点续传）
   */
  async uploadFile(localPath, remotePath, onProgress) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      const stats = fs.statSync(localPath);
      const totalSize = stats.size;
      let uploadedSize = 0;

      // 检查远程文件是否存在
      let remoteSize = 0;
      try {
        const remoteStats = await this.client.size(remotePath);
        remoteSize = remoteStats || 0;
      } catch (error) {
        // 文件不存在，从头开始上传
        remoteSize = 0;
      }

      // 如果远程文件大小与本地相同，跳过上传
      if (remoteSize === totalSize) {
        logger.logFTP('文件已存在且大小相同，跳过上传', { localPath, remotePath });
        if (onProgress) {
          onProgress({ transferred: totalSize, total: totalSize, speed: 0 });
        }
        return { skipped: true, reason: 'same-size' };
      }

      // 设置断点续传起始位置
      uploadedSize = remoteSize > 0 ? remoteSize : 0;

      logger.logFTP('开始上传文件', { localPath, remotePath, totalSize, resumeFrom: uploadedSize });

      // 创建可读流
      const readable = fs.createReadStream(localPath, {
        start: uploadedSize
      });

      let lastTime = Date.now();
      let lastTransferred = uploadedSize;

      // 监听进度
      this.client.trackProgress(info => {
        const now = Date.now();
        const timeElapsed = (now - lastTime) / 1000; // 秒
        const bytesTransferred = info.bytes - lastTransferred;
        const speed = timeElapsed > 0 ? bytesTransferred / timeElapsed : 0;

        if (onProgress) {
          onProgress({
            transferred: uploadedSize + info.bytes,
            total: totalSize,
            speed: speed
          });
        }

        lastTime = now;
        lastTransferred = info.bytes;
      });

      // 上传文件（续传模式）
      if (uploadedSize > 0) {
        await this.client.append(readable, remotePath);
      } else {
        await this.client.uploadFrom(readable, remotePath);
      }

      this.client.trackProgress(); // 停止跟踪

      logger.logFTP('上传文件成功', { localPath, remotePath });
      return { skipped: false };
    } catch (error) {
      this.client.trackProgress(); // 停止跟踪
      logger.logFTP('上传文件失败', { localPath, remotePath, error: error.message });
      throw error;
    }
  }

  /**
   * 下载文件（支持断点续传）
   */
  async downloadFile(remotePath, localPath, onProgress) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      // 获取远程文件大小
      const remoteSize = await this.client.size(remotePath);
      const totalSize = remoteSize || 0;

      // 检查本地文件是否存在
      let localSize = 0;
      if (fs.existsSync(localPath)) {
        const stats = fs.statSync(localPath);
        localSize = stats.size;
      }

      // 如果本地文件已完整，跳过下载
      if (localSize === totalSize && totalSize > 0) {
        logger.logFTP('文件已存在且大小相同，跳过下载', { remotePath, localPath });
        if (onProgress) {
          onProgress({ transferred: totalSize, total: totalSize, speed: 0 });
        }
        return { skipped: true, reason: 'already-exists' };
      }

      logger.logFTP('开始下载文件', { remotePath, localPath, totalSize, resumeFrom: localSize });

      // 创建可写流（追加模式）
      const writable = fs.createWriteStream(localPath, {
        flags: localSize > 0 ? 'a' : 'w',
        start: localSize
      });

      let lastTime = Date.now();
      let lastTransferred = localSize;

      // 监听进度
      this.client.trackProgress(info => {
        const now = Date.now();
        const timeElapsed = (now - lastTime) / 1000;
        const bytesTransferred = info.bytes - lastTransferred;
        const speed = timeElapsed > 0 ? bytesTransferred / timeElapsed : 0;

        if (onProgress) {
          onProgress({
            transferred: localSize + info.bytes,
            total: totalSize,
            speed: speed
          });
        }

        lastTime = now;
        lastTransferred = info.bytes;
      });

      // 下载文件（续传模式）
      await this.client.downloadTo(writable, remotePath, localSize);

      this.client.trackProgress(); // 停止跟踪

      logger.logFTP('下载文件成功', { remotePath, localPath });
      return { skipped: false };
    } catch (error) {
      this.client.trackProgress(); // 停止跟踪
      logger.logFTP('下载文件失败', { remotePath, localPath, error: error.message });
      throw error;
    }
  }

  /**
   * 获取文件大小
   */
  async getFileSize(filePath) {
    if (!this.connected) {
      throw new Error('FTP未连接');
    }

    try {
      const size = await this.client.size(filePath);
      return size;
    } catch (error) {
      logger.logFTP('获取文件大小失败', { filePath, error: error.message });
      return 0;
    }
  }

  /**
   * 检查连接状态
   */
  isConnected() {
    return this.connected;
  }
}

module.exports = FTPClient;
